#include "funcSigmoid.h"

using namespace QPCRModel;

funcSigmoid::funcSigmoid()
{
    a = 1;
    b = 1;
    x0 = 1;
    y0 = 0;
}

int funcSigmoid::getParamNum(){
    return 4;
}

double funcSigmoid::f(double x){
    return y0 + a / (1 + pow(M_E, (x0-x)/b));
}

double funcSigmoid::g(double y){
    if (y <= y0 || y >= a + y0){
        return 0;
    }
    return x0 - b * log(a / (y-y0) -1);
}

double funcSigmoid::loss(double x, double y){
    return y - ( y0 + a / ( 1 + exp((x0-x)/b) ) );
}

double funcSigmoid::loss(double x, double y, const Eigen::VectorXd &X){
    return y - ( X[3] + X[0] / ( 1 + exp((X[2]-x)/X[1]) ) );
}


double funcSigmoid::loss2(double x, double y){
    return pow(y - ( y0 + a / ( 1 + exp((x0-x)/b) ) ), 2);
}


double funcSigmoid::loss2(double x, double y, const Eigen::VectorXd &X){
    return pow(y - ( X[3] + X[0] / ( 1 + exp((X[2]-x)/X[1]) ) ), 2);
}

double funcSigmoid::diff1(double x){
    return (a * exp((x0-x)/b)) / (b * pow(1+exp((x0-x)/b), 2));
}

double funcSigmoid::diff2(double x){
    return (2*a*exp(-(2*(x - x0))/b))/(b*b*pow(exp(-(x - x0)/b) + 1, 3)) - (a*exp(-(x - x0)/b))/(b*b*pow(exp(-(x - x0)/b) + 1, 2));
}

Eigen::VectorXd funcSigmoid::jacobian(double x, double y){
    Eigen::VectorXd res(4);
    res  << -1/(exp((x0 - x)/b) + 1),
            -(a*exp((x0 - x)/b)*(x0 - x))/(b*b*pow(exp((x0 - x)/b) + 1, 2)),
            (a*exp((x0 - x)/b))/(b*pow(exp((x0 - x)/b) + 1, 2)),
            -1;
    return res;
}

Eigen::VectorXd funcSigmoid::jacobian2(double x, double y){
    Eigen::VectorXd res(4);

    res  << (2*(y0 - y + a/(exp((x0 - x)/b) + 1)))/(exp((x0 - x)/b) + 1),
            (2*a*exp((x0 - x)/b)*(x0 - x)*(y0 - y + a/(exp((x0 - x)/b) + 1)))/(b*b*pow(exp((x0 - x)/b) + 1, 2)),
            -(2*a*exp((x0 - x)/b)*(y0 - y + a/(exp((x0 - x)/b) + 1)))/(b*pow(exp((x0 - x)/b) + 1, 2)),
            2*y0 - 2*y + (2*a)/(exp((x0 - x)/b) + 1);
    return res;
}


void funcSigmoid::setV(const Eigen::VectorXd &v){
    a = v[0];
    b = v[1];
    x0 = v[2];
    y0 = v[3];
}

Eigen::VectorXd funcSigmoid::getV(){
    Eigen::VectorXd res(4);
    res << this->a, this->b, this->x0, this->y0;
    return res;
}

double funcSigmoid::getLinearStageFunc(double *lk, double *lb){

    *lk = a / (4*b);
    *lb = - x0 * (*lk) + f(x0);

    return *lk;
}

double funcSigmoid::curvity(double x, double norm_coef){
    if(norm_coef <= 0){
        norm_coef = a;
    }
    double res = -((norm_coef*exp(-(x - x0)/b))/pow(b*b*(exp(-(x - x0)/b) + 1), 2) -(2*norm_coef*exp(-(2*(x - x0))/b))/(b*b*pow(exp(-(x - x0)/b) + 1, 3)))/pow((norm_coef*norm_coef*exp(-(2*x - 2*x0)/b))/(b*b*pow(exp(-(x - x0)/b) + 1, 4)) + 1, 1.5);
    return res;
}

std::pair<double, double> funcSigmoid::getRange(int i){
    if(i == 0){
        return std::pair<double, double>(0, INFINITY);
    }else if(i == 1){
        return std::pair<double, double>(0.4, 100);
    }else if(i == 2){
        return std::pair<double, double>(0, 60);
    }else if(i == 3){
        return std::pair<double, double>(0, INFINITY);
    }else{
        return std::pair<double, double>(-INFINITY, INFINITY);
    }
}


void funcSigmoid::init(double SPE, double EPE, int cycleNum, double ymin, double ymax){

    // 根据findExp2函数，SPE和EPE定义为线性期两侧斜率小于2的点

    if(EPE > cycleNum){
        a = (ymax - ymin) * 2;
    }else{
        a = (ymax - ymin);
    }

    b = 2;

    x0 = (SPE + EPE) / 2;
    y0 = ymin;


}
